#include "RacingHUDApp.h"
#include <QVariant>
#include <QTime>

RacingHUDApp::RacingHUDApp(QObject* parent) : QObject(parent) 
{ 
    m_udpSocket = new QUdpSocket(this);
    m_udpSocket->bind(QHostAddress::Any, 20777);
    connect(m_udpSocket, &QUdpSocket::readyRead, this, &RacingHUDApp::processPendingDatagrams);
}
QObject *RacingHUDApp::viewModel() const
{
    return m_viewModel;
}

void RacingHUDApp::setViewModel(QObject *newViewModel)
{
    if (m_viewModel == newViewModel)
        return;
    m_viewModel = newViewModel;
    emit viewModelChanged();
}

QString gearToString(int8_t gear) 
{
    switch (gear) {
        case -1: return "R"; // Reverse
        case 0: return "N"; // Neutral
        default: return QString::number(gear); // Drive 
    }

    return QString::number(gear);
}

void RacingHUDApp::processCarTelemetryData(const CarTelemetryData &carTelemetryData)
{
    if(viewModel() == nullptr) 
        return;

    viewModel()->setProperty("revLightsPercent", carTelemetryData.m_revLightsPercent);
    viewModel()->setProperty("drsEnabled", carTelemetryData.m_drs);
    viewModel()->setProperty("gear", gearToString(carTelemetryData.m_gear));
    viewModel()->setProperty("speed", carTelemetryData.m_speed);
    QList<QVariant> tyreTemperatures({carTelemetryData.m_tyresSurfaceTemperature[0], carTelemetryData.m_tyresSurfaceTemperature[1], 
        carTelemetryData.m_tyresSurfaceTemperature[2], carTelemetryData.m_tyresSurfaceTemperature[3]});
    viewModel()->setProperty("tyreTemperatures", tyreTemperatures);
}

void RacingHUDApp::processCarStatusData(const CarStatusData &carStatusData)
{
    if(viewModel() == nullptr)  
        return;

    // 设置车辆状态数据到视图模型
    viewModel()->setProperty("fuel", carStatusData.m_fuelInTank);
    viewModel()->setProperty("ersDeployMode", carStatusData.m_ersDeployMode);
    viewModel()->setProperty("ersStoreEnergy", carStatusData.m_ersStoreEnergy);
    viewModel()->setProperty("ersHarvestedThisLap", carStatusData.m_ersHarvestedThisLapMGUK + carStatusData.m_ersHarvestedThisLapMGUH);
    viewModel()->setProperty("ersDeployedThisLap", carStatusData.m_ersDeployedThisLap);
}

QString floatTimeToString(float seconds)
{
    QTime time = QTime(0, 0).addMSecs(static_cast<int>(seconds * 1000));
    if (time.isNull()) {
        return "00:00.000"; // 如果时间无效，返回默认值
    }

    return time.toString("mm:ss.zzz");
}

void RacingHUDApp::processLapData(PacketLapData &lapData)
{
    if(viewModel() == nullptr)  
        return;

    int playerIndex = lapData.m_header.m_playerCarIndex;
    if (playerIndex < 0 || playerIndex >= 20) {
        qWarning("Invalid player index: %d", playerIndex);
        return;
    }

    auto playerPos = lapData.m_lapData[playerIndex].m_carPosition;

    std::sort(lapData.m_lapData, lapData.m_lapData + 20, [](const LapData &a, const LapData &b) {
        return a.m_carPosition < b.m_carPosition;
    });

    playerIndex = playerPos - 1; // Adjust for 0-based index
    if (playerIndex < 0 || playerIndex >= 20) {
        qWarning("Invalid player index after sorting: %d", playerIndex);
        return;
    }
    
    viewModel()->setProperty("lapNum", lapData.m_lapData[playerIndex].m_currentLapNum);
    viewModel()->setProperty("carPos", playerPos);
    viewModel()->setProperty("currentLapTimeStr", floatTimeToString(lapData.m_lapData[playerIndex].m_currentLapTime));

    // 仅当玩家不位于第一名时才计算与前车的差距
    // 注意：这里假设车手的排名是从1开始的，所以如果玩家在第1名，则没有前车
    if(playerPos > 1) {
       auto frontCarIndex = playerIndex - 1;
       if(frontCarIndex >= 0 && frontCarIndex < 20) {
           auto frontCarData = lapData.m_lapData[frontCarIndex];
           viewModel()->setProperty("frontDiffTimeStr", floatTimeToString(frontCarData.m_currentLapTime - lapData.m_lapData[playerIndex].m_currentLapTime));
        }
    }
    else {
        viewModel()->setProperty("frontDiffTimeStr", "N/A");
    }

    // 仅当玩家不位于最后一名时才计算与后车的差距
    // 注意：这里假设车手的排名是从1开始的，所以如果玩家在第20名，则没有后车
    if(playerPos < 20) {
       auto backCarIndex = playerIndex + 1;
       if(backCarIndex >= 0 && backCarIndex < 20) {
           auto backCarData = lapData.m_lapData[backCarIndex];
           viewModel()->setProperty("backDiffTimeStr", floatTimeToString(lapData.m_lapData[playerIndex].m_currentLapTime - backCarData.m_currentLapTime));
       }
    }
    else {
        viewModel()->setProperty("backDiffTimeStr", "N/A");
    }
}

void RacingHUDApp::processPendingDatagrams() {
    // 读取数据报，尝试将数据报的前sizeof(PacketHeader)字节解析为PacketHeader结构体
    while (m_udpSocket->hasPendingDatagrams()) {
        QByteArray datagram;
        datagram.resize(m_udpSocket->pendingDatagramSize());
        m_udpSocket->readDatagram(datagram.data(), datagram.size());

        // 尝试解析数据报
        PacketHeader header;
        if (datagram.size() >= sizeof(PacketHeader)) {
            memcpy(&header, datagram.data(), sizeof(PacketHeader)); // 解析数据报头
            if (header.m_packetFormat != 2019) 
                return;
            
            if(!viewModel())
                return;

            switch (header.m_packetId) {
                case PKT_CAR_TELEMETRY:
                {
                    PacketCarTelemetryData *telemetryData = (PacketCarTelemetryData*)(datagram.data());
                    CarTelemetryData playerCarData = telemetryData->m_carTelemetryData[header.m_playerCarIndex];
                    processCarTelemetryData(playerCarData);
                    break;
                } 

                case PKT_CAR_STATUS:
                {
                    const PacketCarStatusData *statusData = (PacketCarStatusData*)(datagram.data());
                    CarStatusData playerCarData = statusData->m_carStatusData[header.m_playerCarIndex]; 
                    processCarStatusData(playerCarData);
                    break;
                }

                case PKT_LAP_DATA:
                {
                    break;

                    PacketLapData lapData;
                    if (datagram.size() >= sizeof(PacketLapData)) {
                        memcpy(&lapData, datagram.data(), sizeof(PacketLapData)); // 解析圈速数据
                        processLapData(lapData);
                    }
                }

                default:
                    break;
            }
            
        } 
    }
}